package gopack

import (
	"bytes"
	"encoding/binary"
	"errors"
)

// The protocol is pack and unpack of promise
type Protocol struct {
	Format []string
}

// 打包
func (pro *Protocol) Pack(args ...interface{}) ([]byte, error) {
	lenArgs := len(args)
	lenFormat := len(pro.Format)
	result := make([]byte, 0)
	if lenArgs <= 0 || lenArgs != lenFormat {
		return result, errors.New("规则与参数长度不一致")
	}
	for i, value := range args {
		switch pro.Format[i] {
		case "v":
			toByte, err := vToByte(value.(int16))
			if err != nil {
				return result, err
			}
			result = append(result, toByte...)
		case "n":
			toByte, err := nToByte(value.(int16))
			if err != nil {
				return result, err
			}
			result = append(result, toByte...)
		case "V":
			toByte, err := bigVToByte(value.(int32))
			if err != nil {
				return result, err
			}
			result = append(result, toByte...)
		case "N":
			toByte, err := bigNToByte(value.(int32))
			if err != nil {
				return result, err
			}
			result = append(result, toByte...)
		case "J":
			toByte, err := bigJToByte(value.(int64))
			if err != nil {
				return result, err
			}
			result = append(result, toByte...)
		case "p":
			toByte, err := pToByte(value.(int64))
			if err != nil {
				return result, err
			}
			result = append(result, toByte...)
		case "c", "C":
			result = append(result, []byte(value.(string))...)
		default:
			return result, errors.New("未知的转换类型")
		}
	}
	return result, nil
}

// 解包
func (pro *Protocol) Unpack(content []byte) ([]interface{}, error) {
	lenFormat := len(pro.Format)
	result := make([]interface{}, lenFormat)
	if lenFormat <= 0 || len(content) <= 0 {
		return result, errors.New("无效的参数")
	}
	for i, value := range pro.Format {
		byteSize := size(value)
		switch value {
		case "v":
			i2, err := v(content[0:byteSize])
			if err != nil {
				return result, err
			}
			result[i] = i2
		case "n":
			i2, err := n(content[0:byteSize])
			if err != nil {
				return result, err
			}
			result[i] = i2
		case "V":
			i2, err := bigV(content[0:byteSize])
			if err != nil {
				return result, err
			}
			result[i] = i2
		case "N":
			i2, err := bigN(content[0:byteSize])
			if err != nil {
				return result, err
			}
			result[i] = i2
		case "J":
			i2, err := bigJ(content[0:byteSize])
			if err != nil {
				return result, err
			}
			result[i] = i2
		case "p":
			i2, err := p(content[0:byteSize])
			if err != nil {
				return result, err
			}
			result[i] = i2
		case "c", "C":
			stringSize := changeType(result[i-1])
			if stringSize == 0 {
				return result, errors.New("错误的类型")
			}
			result[i] = string(content[0:stringSize])
			content = content[stringSize:]

		default:
			return result, errors.New("未知的转换类型")
		}
		content = content[byteSize:]
		if len(content) == 0 && i+1 != lenFormat {
			return result, errors.New("缺少数据")
		}
	}
	return result, nil
}

// 改变类型
func changeType(data interface{}) int {
	switch data.(type) {
	case int16:
		return int(data.(int16))
	case int32:
		return int(data.(int32))
	case int:
		return data.(int)
	}
	return 0
}

// 判断类型的大小
func size(parameter string) int {
	size := 0
	switch parameter {
	case "v", "n":
		size = 2
	case "V", "N":
		size = 4
	case "J", "p":
		size = 8
	}
	return size
}

// v 无符号短整型(16位，小端字节序)
func v(b []byte) (int16, error) {
	var x int16
	bytesBuffer := bytes.NewBuffer(b)
	err := binary.Read(bytesBuffer, binary.LittleEndian, &x)
	return int16(x), err
}

// int16 转byte
func vToByte(n int16) ([]byte, error) {
	bytesBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(bytesBuffer, binary.LittleEndian, int16(n))
	return bytesBuffer.Bytes(), err
}

// n 无符号短整型(16位，大端字节序)
func n(b []byte) (int16, error) {
	var x int16
	bytesBuffer := bytes.NewBuffer(b)
	err := binary.Read(bytesBuffer, binary.BigEndian, &x)
	return int16(x), err
}

func nToByte(n int16) ([]byte, error) {
	bytesBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(bytesBuffer, binary.BigEndian, int16(n))
	return bytesBuffer.Bytes(), err
}

// V 无符号长整型(32位，小端字节序)
func bigV(b []byte) (int32, error) {
	var x int32
	bytesBuffer := bytes.NewBuffer(b)
	err := binary.Read(bytesBuffer, binary.LittleEndian, &x)
	return int32(x), err
}

func bigVToByte(x int32) ([]byte, error) {
	bytesBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(bytesBuffer, binary.LittleEndian, int32(x))
	return bytesBuffer.Bytes(), err
}

// 	N 无符号长整型(32位，大端字节序)
func bigN(b []byte) (int32, error) {
	var x int32
	bytesBuffer := bytes.NewBuffer(b)
	err := binary.Read(bytesBuffer, binary.BigEndian, &x)
	return int32(x), err
}

func bigNToByte(n int32) ([]byte, error) {
	bytesBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(bytesBuffer, binary.BigEndian, int32(n))
	return bytesBuffer.Bytes(), err
}

// J 无符号长长整型(64位，大端字节序)
func bigJ(b []byte) (int64, error) {
	var x int64
	bytesBuffer := bytes.NewBuffer(b)
	err := binary.Read(bytesBuffer, binary.BigEndian, &x)
	return int64(x), err
}

func bigJToByte(n int64) ([]byte, error) {
	bytesBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(bytesBuffer, binary.BigEndian, int64(n))
	return bytesBuffer.Bytes(), err
}

// P 无符号长长整型(64位，小端字节序)
func p(b []byte) (int64, error) {
	var x int64
	bytesBuffer := bytes.NewBuffer(b)
	err := binary.Read(bytesBuffer, binary.LittleEndian, &x)
	return int64(x), err
}

func pToByte(n int64) ([]byte, error) {
	bytesBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(bytesBuffer, binary.LittleEndian, int64(n))
	return bytesBuffer.Bytes(), err
}
